package com.cloud.consumer.feign.rule;

import com.alibaba.fastjson.JSON;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @ClassName: MyRule
 * @Author: wl
 * @Date: 2021/11/23 11:01
 * @Description: TODO
 */
public class MyRule2 extends AbstractLoadBalancerRule {

    private AtomicInteger nextServerCyclicCounter;
    private static final boolean AVAILABLE_ONLY_SERVERS = true;
    private static final boolean ALL_SERVERS = false;

    // 记录请求次数
    private AtomicInteger reqCounter;

    // 单个服务调用次数,达到次数后进行切换
    private static final Integer singleRoundCount = 5;

    private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);

    public MyRule2() {
        nextServerCyclicCounter = new AtomicInteger(0);
        reqCounter = new AtomicInteger(0);
    }

    public MyRule2(ILoadBalancer lb) {
        this();
        setLoadBalancer(lb);
    }

    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        }

        Server server = null;
        int count = 0;
        while (server == null && count++ < 10) {
            List<Server> reachableServers = lb.getReachableServers();
            List<Server> allServers = lb.getAllServers();
            System.out.println("服务器列表:" + JSON.toJSONString(allServers));

            int upCount = reachableServers.size();
            int serverCount = allServers.size();

            if ((upCount == 0) || (serverCount == 0)) {
                log.warn("No up servers available from load balancer: " + lb);
                return null;
            }

            int nextServerIndex = incrementAndGetModulo(serverCount);
            System.out.println("服务器位置:" + nextServerIndex);
            server = allServers.get(nextServerIndex);
            reqCounter.getAndIncrement();
            System.out.println("调用的服务端口:"+server.getPort() + ", 轮询次数:" + reqCounter.get());

            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

            if (server.isAlive() && (server.isReadyToServe())) {
                return (server);
            }

            // Next.
            server = null;
        }

        if (count >= 10) {
            log.warn("No available alive servers after 10 tries from load balancer: "
                    + lb);
        }

        return server;
    }

    /**
     * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}.
     *
     * @param modulo The modulo to bound the value of the counter.
     * @return The next value.
     */
    private int incrementAndGetModulo(int modulo) {
        for (;;) {
            int current = nextServerCyclicCounter.get();

            // 如果有服务下线,当前下标大于等于服务数量
            if (current >= modulo) {
                nextServerCyclicCounter.compareAndSet(current, modulo - 1);
                current =  modulo - 1;
            }

            if (reqCounter.get() % singleRoundCount != 0) {
                return current;

            }
            reqCounter.getAndSet(0);
            int next = (current + 1) % modulo;
            if (nextServerCyclicCounter.compareAndSet(current, next))
                return next;
        }
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }

}
